#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <pthread.h>
using std::string;
#include "log.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"
#include "deamon.hpp"
#define BUFFERSIZE 1024

extern Log lg;
const int backlog = 10; // 但是一般不要设置的太大

enum
{
    UsageError = 1,
    SocketError,
    BindError,
    ListenError,
};

class TcpServer;

struct thread_data
{
public:
    thread_data(sockaddr_in c, int fd, TcpServer *t)
        : client(c), rwfd(fd), TcpServer_this(t)
    {
    }
    struct sockaddr_in client;
    int rwfd;
    TcpServer *TcpServer_this;
};

class TcpServer
{
public:
    TcpServer(size_t _localport)
        : listenfd_(0), localport_(_localport)
    {
        tp->getInstance()->run();
    }
    void init()
    {
        listenfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd_ == -1)
        {
            lg(FATAL, "listenfd create error!");
            exit(SocketError);
        }
        lg(INFO, "listenfd create success!");

        int opt = 1;
        setsockopt(listenfd_, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)

        struct sockaddr_in server;
        server.sin_addr.s_addr = INADDR_ANY;
        server.sin_family = AF_INET; // ipv4
        server.sin_port = htons(localport_);
        socklen_t addrlen = sizeof(server);

        if (bind(listenfd_, (sockaddr *)&server, addrlen))
        {
            lg(FATAL, "bind error:%d-%s", errno, strerror(errno));
            exit(1);
        }
        lg(INFO, "bind success:%d-%s", errno, strerror(errno));

        if (listen(listenfd_, backlog))
        {
            lg(FATAL, "listen error:%d-%s", errno, strerror(errno));
            exit(1);
        }
        lg(INFO, "listen success:%d-%s", errno, strerror(errno));
    }

    // static void *thread_fun(void *argv)
    // {
    //     pthread_detach(pthread_self());
    //     thread_data *td = static_cast<thread_data *>(argv);
    //     td->TcpServer_this->service(td->rwfd, td->client);
    //     delete td;
    //     return nullptr;
    // }

    void run()
    {
        while (true) // 这里和下面为什么要加两个while
        {
            sockaddr_in client;
            socklen_t client_len = sizeof(client);
            int rwfd = accept(listenfd_, (sockaddr *)&client, &client_len);
            if (rwfd < 0)
            {
                lg(WARNING, "accept error %d:%s", errno, strerror(errno));
                continue;
            }
            uint16_t client_port = ntohs(client.sin_port);
            char client_ip[32];
            inet_ntop(AF_INET, &client.sin_addr, client_ip, sizeof(client_ip));
            lg(INFO, "get a link, sockfd:%d ip:%s port:%d ", rwfd, client_ip, client_port);
            // 单进程版本！
            // service(rwfd, client);

            // 多进程版
            // pid_t pid = fork();
            // if (pid == 0)
            // {
            //     close(listenfd_);
            //     if (fork() > 0)
            //     {
            //         // 这样会让子进程退出，孙子进程执行任务，孙子进程被系统托管
            //         exit(0);
            //     }
            //     service(rwfd, client);
            //     exit(0);
            // }
            // close(rwfd);
            // waitpid(pid, nullptr, 0);

            // 多线程版 -- 需要优化的点：等到客户来再开线程就太慢了
            // 避免用户长期不退出，浪费资源，改成短服务
            // pthread_t tid;
            // thread_data *td = new thread_data(client, rwfd, this);
            // pthread_create(&tid, nullptr, thread_fun, td);

            // 线程池版
            Task t(rwfd, client_ip, client_port);
            tp->getInstance()->PushTask(t);
            // close(rwfd);
        }
    }

    // void service(const int _rwfd, const sockaddr_in _client) // 这里和上面为什么要加两个while呢？一个不可以吗
    // {
    //     char inbuffer[1024];
    //     while (true)
    //     {
    //         int n = read(_rwfd, inbuffer, sizeof(inbuffer) - 1);
    //         inbuffer[n] = 0;
    //         if (n <= 0)
    //             return;
    //         // 处理字符串
    //         string handled_str;
    //         char clientIP[32];
    //         inet_ntop(AF_INET, &(_client.sin_addr), clientIP, sizeof(clientIP));
    //         uint16_t clientPort = ntohs(_client.sin_port);
    //         handled_str += "[";
    //         handled_str += clientIP;
    //         handled_str += ":";
    //         handled_str += std::to_string(clientPort);
    //         handled_str += "]:";
    //         handled_str += inbuffer;
    //         std::cout << handled_str << std::endl;
    //         write(_rwfd, handled_str.c_str(), handled_str.size());
    //     }
    // }

private:
    int listenfd_;
    uint16_t localport_;
    ThreadPool<Task> *tp;
};